#include <zenocli/main.hpp>
#include <zeno3rd/cxxopts.hpp>
#include <zenox/minilog.hpp>
#include <zenox/home.hpp>
#include <zenox/unicode.hpp>
#include <zenox/subroutine.hpp>
#include <iostream>

namespace zenocli {

ZENO_COLD_FN static void show_version_info() {
    std::cerr << "Zeno (C) 2023 Zenus Technology" << std::endl;
#if defined(ZENO_VERSION_MAJOR) && defined(ZENO_VERSION_MINOR) && defined(ZENO_VERSION_PATCH)
    std::cerr << "Version: " << ZENO_VERSION_MAJOR << "." << ZENO_VERSION_MINOR << "." << ZENO_VERSION_PATCH << std::endl;
#else
    std::cerr << "Version: (no version info available)" << std::endl;
#endif
    std::cerr << "Build: " << zenox::zeno_build_date() << std::endl;
    std::cerr << "Flags:"
#ifdef ZENO_PLATFORM_ID
    " -DZENO_PLATFORM_ID=" ZENO_PLATFORM_ID
#endif
#ifdef ZENO_COMPILER_ID
    " -DZENO_COMPILER_ID=" ZENO_COMPILER_ID
#endif
#ifdef ZENO_BUILD_TYPE
    " -DZENO_BUILD_TYPE=" ZENO_BUILD_TYPE
#endif
#ifdef ZENO_BUILD_CONFIG
    " -DZENO_BUILD_CONFIG=" ZENO_BUILD_CONFIG
#endif
#ifdef NDEBUG
    " -DNDEBUG"
#endif
#ifdef ZENO_SOURCE_DIR
    " -DZENO_SOURCE_DIR=" ZENO_SOURCE_DIR
#endif
#ifdef ZENO_SYSTEM_TBB_VERSION
    " -DZENO_SYSTEM_TBB_VERSION=" ZENO_SYSTEM_TBB_VERSION
#endif
#ifdef ZENO_SYSTEM_ZLIB_VERSION
    " -DZENO_SYSTEM_ZLIB_VERSION=" ZENO_SYSTEM_ZLIB_VERSION
#endif
#ifdef ZENO_HAS_TBBMALLOC_PROXY
    " -DZENO_HAS_TBBMALLOC_PROXY"
#endif
#ifdef ZENO_HAS_MIMALLOC
    " -DZENO_HAS_MIMALLOC"
#endif
#ifdef ZENO_HAS_BACKWARD_CPP
    " -DZENO_HAS_BACKWARD_CPP"
#endif
#ifdef ZENO_HAS_OPENMP
    " -DZENO_HAS_OPENMP"
#endif
#ifdef ZENO_HAS_AVX2
    " -DZENO_HAS_AVX2"
#endif
#ifdef ZENO_HAS_FAST_MATH
    " -DZENO_HAS_FAST_MATH"
#endif
#ifdef ZENO_HAS_CPP20_FORMAT
    " -DZENO_HAS_CPP20_FORMAT"
#endif
#ifdef ZENO_HAS_SPLASH
    " -DZENO_HAS_SPLASH"
#endif
#ifdef ZENO_MINILOG_DISABLE
    " -DZENO_MINILOG_DISABLE"
#endif
    << std::endl;
}

int main(int argc, char **argv) {
    cxxopts::Options opts(argv[0], "Welcome to the Zeno CLI interface");;
    opts.add_options()
        ("h,help", "print usage")
        ("v,version", "query program version")
        ("V,verbose", "verbose log output")
        ("s,subprogram", "run CLI sub-program", cxxopts::value<std::string>())
        ;
    cxxopts::ParseResult res;
    try {
        res = opts.parse(argc, argv);
    } catch (std::exception const &e) {
        std::cerr << "invalid command line argument: " << e.what() << std::endl;
        return -1;
    }
    if (res.count("verbose")) {
        zenox::logger::default_logger().set_log_level(zenox::log_level::trace);
    }
    if (res.count("help")) {
        std::cerr << opts.help() << std::endl;
        return 0;
    }
    if (res.count("version")) {
        show_version_info();
        return 0;
    }

    auto unmatched = res.unmatched();
    std::vector<char *> umatched_cstr;
    umatched_cstr.reserve(unmatched.size() + 2);
    umatched_cstr.push_back(argv[0]);
    for (auto arg: unmatched) {
        umatched_cstr.push_back((char *)arg.c_str());
    }
    umatched_cstr.push_back(nullptr);
    argc = umatched_cstr.size() - 1;
    argv = umatched_cstr.data();

    std::string program = "ui";
    if (auto p = std::getenv("ZENO_DEFAULT_SUBPROGRAM")) {
        program = p;
    }
    if (res.count("subprogram")) {
        program = res["subprogram"].as<std::string>();
    }
    return zenox::SubprogramRegistry::call(program, argc, argv);
}

}
